/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#ifndef MC_TEST_WX_COMMON_H
#define MC_TEST_WX_COMMON_H

#include <devmon/driver_abi.h>
#include <dlfcn.h>
#include <functional>
#include <gtest/gtest.h>
#include <test_utilities/test_base.h>
#include <mc/common.h>
#include <ncsi_over_mctp/ncsi_over_mctp_wx.h>
#include <mctp/mctp.h>
#include <imu/imu.h>
#include <ipmb/ipmb.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
#include <thread>
#include <chrono>

#include "pcie_nic_card/wx/wx_card.h"
#include "pcie_nic_card/wx/wx_port.h"

using namespace dev;

namespace drivers {
namespace pcie_nic_card {
namespace wx {
namespace test {

// IMU响应类型枚举
enum class ImuResponseType {
    SUCCESS,           // 返回有效数据
    NULL_RESPONSE,     // 返回nullopt（通过返回失败完成码）
    SHORT_DATA,        // 返回数据长度不足
    INVALID_VID_DID,   // 返回无效的VID/DID (0xFFFF)
    INVALID_SVID_SDID  // 返回无效的SVID/SDID (0xFFFF)
};

class test_interface : public mc::engine::interface<test_interface> {
public:
    MC_INTERFACE("bmc.kepler.IpmiCore")

    //a{ss}yyyyyay
    mc::variant Request(
        const mc::dict& ctx,              // a{ss} - 上下文字典
        uint8_t channel_type,              // y - 通道类型
        uint8_t instance,                  // y - 实例序号
        uint8_t net_fn,                   // y - 网络功能码
        uint8_t lun,                      // y - 逻辑单元号
        uint8_t cmd,                      // y - 命令字
        const std::vector<uint8_t>& data  // ay - 命令参数数据
    ) {
        // 只处理 PMU PCI 请求（net_fn=oem, cmd=0x44）
        if (net_fn != static_cast<uint8_t>(mc::ipmi_net_fn::oem) || cmd != 0x44) {
            // 对于其他请求，返回默认响应
            mc::variants result = {mc::variant(0), mc::variant(std::vector<uint8_t>{})};
            return mc::variant(result);
        }

        // 解析请求数据：{0xDB, 0x07, 0x00, cpu_id, addr1, addr2, addr3, addr4, length}
        if (data.size() < 9) {
            // 数据长度不足，返回失败
            mc::variants result = {mc::variant(static_cast<uint8_t>(mc::ipmi_completion_code::invalid_data_field)), 
                                   mc::variant(std::vector<uint8_t>{})};
            return mc::variant(result);
        }

        uint8_t addr1 = data[3]; // PCI地址1，用于判断是VID/DID还是SVID/SDID请求
        ImuResponseType response_type;
        
        if (addr1 == dev::VID_DID_ADDRESS) {
            response_type = m_vid_did_response_type;
        } else if (addr1 == dev::SVID_SDID_ADDRESS) {
            response_type = m_svid_sdid_response_type;
        } else {
            // 未知地址，返回失败
            mc::variants result = {mc::variant(static_cast<uint8_t>(mc::ipmi_completion_code::invalid_data_field)), 
                                   mc::variant(std::vector<uint8_t>{})};
            return mc::variant(result);
        }

        // 根据响应类型返回不同的响应
        if (response_type == ImuResponseType::NULL_RESPONSE) {
            // 返回失败完成码，模拟nullopt
            mc::variants result = {mc::variant(static_cast<uint8_t>(mc::ipmi_completion_code::node_busy)), 
                                   mc::variant(std::vector<uint8_t>{})};
            return mc::variant(result);
        }

        // 构造响应数据：{0xDB, 0x07, 0x00, ...data...}
        std::vector<uint8_t> response_data = {0xDB, 0x07, 0x00};

        if (response_type == ImuResponseType::SHORT_DATA) {
            // 返回短数据（只有3字节，不足4字节）
            response_data.push_back(0x01);
            response_data.push_back(0x02);
            response_data.push_back(0x03);
        } else if (response_type == ImuResponseType::INVALID_VID_DID || 
                   response_type == ImuResponseType::INVALID_SVID_SDID) {
            // 返回无效值 0xFFFF
            response_data.push_back(0xFF);
            response_data.push_back(0xFF);
            response_data.push_back(0xFF);
            response_data.push_back(0xFF);
        } else {
            // 返回有效数据
            if (addr1 == dev::VID_DID_ADDRESS) {
                // VID=0x19e5, DID=0x1822 (little-endian)
                response_data.insert(response_data.end(), m_vid_did_data.begin(), m_vid_did_data.end());
            } else {
                // SVID=0x19e5, SDID=0x1823 (little-endian)
                response_data.insert(response_data.end(), m_svid_sdid_data.begin(), m_svid_sdid_data.end());
            }
        }

        mc::variants result = {mc::variant(static_cast<uint8_t>(mc::ipmi_completion_code::success)), 
                               mc::variant(response_data)};
        return mc::variant(result);
    }

    void set_vid_did_response_type(ImuResponseType type) { m_vid_did_response_type = type; }
    void set_svid_sdid_response_type(ImuResponseType type) { m_svid_sdid_response_type = type; }
    void set_response_type(ImuResponseType type) { 
        m_vid_did_response_type = type;
        m_svid_sdid_response_type = type;
    }
    void set_vid_did_data(const std::vector<uint8_t>& data) { m_vid_did_data = data; }
    void set_svid_sdid_data(const std::vector<uint8_t>& data) { m_svid_sdid_data = data; }

private:
    ImuResponseType m_vid_did_response_type = ImuResponseType::SUCCESS;
    ImuResponseType m_svid_sdid_response_type = ImuResponseType::SUCCESS;
    std::vector<uint8_t> m_vid_did_data{0xe5, 0x19, 0x22, 0x18};  // VID=0x19e5, DID=0x1822 (little-endian)
    std::vector<uint8_t> m_svid_sdid_data{0xe5, 0x19, 0x23, 0x18}; // SVID=0x19e5, SDID=0x1823 (little-endian)
};
    
class test_object : public mc::engine::object<test_object> {
public:
    MC_OBJECT(test_object, "bmc.kepler.IpmiCore", "/bmc/kepler/IpmiCore", (test_interface))

    test_interface m_test_interface;
};

// 测试服务类
class wx_test_service : public mc::engine::service {
public:
    wx_test_service(const std::string& name) : mc::engine::service(name) {}
};

// 公共测试基类
class WxAbiTest : public mc::test::TestWithEngine {
public:
    static void SetUpTestSuite() {
        TestWithEngine::SetUpTestSuite();
        m_test_service.init();
        m_test_service.start();
        m_test_obj = test_object::create();
        m_test_obj->set_object_path("/bmc/kepler/IpmiCore");
        m_test_obj->set_object_name("bmc.kepler.IpmiCore");
        m_test_service.register_object(m_test_obj);
        m_mctp = mc::make_shared<dev::mctp>(nullptr, 0, dev::MCTP_MESSAGE_TYPE_NCSI, "");
        load_driver();
    }

    static void TearDownTestSuite() {
        m_test_service.stop();
        if (m_driver_handle != nullptr) {
            dlclose(m_driver_handle);
            m_driver_handle = nullptr;
        }
        TestWithEngine::TearDownTestSuite();
    }

    void SetUp() override {}

    void TearDown() override {}

    static void load_driver() {
        m_driver_handle = dlopen("./opt/bmc/drivers/libwx.so", RTLD_LAZY);
        if (m_driver_handle == nullptr) {
            MC_THROW(mc::system_exception, "Failed to load driver: ${error}", ("error", dlerror()));
        }
        register_device_driver_func func = reinterpret_cast<register_device_driver_func>(
            dlsym(m_driver_handle, "register_device_driver"));
        MC_ASSERT_THROW(func, mc::bad_function_call_exception,
                        "Failed to get register_device_driver function: ${error}",
                        ("error", dlerror()));

        device_driver_t* devices       = nullptr;
        uint8_t          devices_count = 0;
        status_t         ret           = func(&devices, &devices_count);
        MC_ASSERT_THROW(ret == STATUS_OK, mc::bad_function_call_exception,
                        "Failed to get device driver manager: ${error}", ("error", ret));

        m_devices.clear();
        m_devices.reserve(devices_count);
        for (uint8_t i = 0; i < devices_count; i++) {
            auto device_driver = std::make_shared<device_driver_t>(devices[i]);
            m_devices.emplace(device_driver->device_name, device_driver);
        }
    }

    mc::dict create_test_connector(uint8_t system_id = 1, uint8_t position = 1, uint8_t slot = 1) {
        return mc::dict{{"SystemId", system_id}, {"Position", position}, {"Slot", slot}};
    }

    mc::mutable_dict create_test_csr() {
        return mc::mutable_dict{{"SystemId", 1}};
    }

    static wx_test_service                                               m_test_service;
    static std::unordered_map<std::string, std::shared_ptr<device_driver_t>> m_devices;
    static void*                                                             m_driver_handle;
    static mc::shared_ptr<test_object>                                     m_test_obj;
    static mc::shared_ptr<dev::mctp>                                        m_mctp;
};

// 静态成员初始化
inline wx_test_service WxAbiTest::m_test_service{"bmc.kepler.ipmi_core"};
inline std::unordered_map<std::string, std::shared_ptr<device_driver_t>> WxAbiTest::m_devices;
inline void* WxAbiTest::m_driver_handle = nullptr;
inline mc::shared_ptr<test_object> WxAbiTest::m_test_obj = nullptr;
inline mc::shared_ptr<dev::mctp> WxAbiTest::m_mctp = nullptr;

} // namespace test
} // namespace wx
} // namespace pcie_nic_card
} // namespace drivers

#endif // MC_TEST_WX_COMMON_H

